package com.penglecode.reflection.jdk;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import com.penglecode.reflection.bean.Product;

public class JDKReflectionTest {

	/**
	 * 基于标准javabean属性的标准get、set方法来操作其属性值
	 * @throws Exception
	 */
	public static void testJDKNormalGetAndSet() throws Exception {
		Product product = new Product();
		long startTimeMillis = System.currentTimeMillis();
		for(int i = 0; i < 100000000; i++){
			long value = product.getProductId();
			product.setProductId(value);
		}
		long endTimeMillis = System.currentTimeMillis();
		System.out.println(">>> total cost : " + (endTimeMillis - startTimeMillis) + " ms");
	}
	
	/**
	 * 基于java.lang.reflect.Field的get(),set()方法操作对象的属性
	 * total cost : 15151 ms AVG
	 */
	public static void testJDKReflection1() throws Exception {
		Product product = new Product();
		long startTimeMillis = System.currentTimeMillis();
		Class<?> clazz = Product.class;
		Field[] fields = clazz.getDeclaredFields();
		Map<String,Field> fieldMap = new HashMap<String,Field>();
		for(Field field : fields){
			field.setAccessible(true);
			fieldMap.put(field.getName(), field);
		}
		for(int i = 0; i < 100000000; i++){
			Field f = fieldMap.get("productId");
			Object value = f.get(product);
			f.set(product, value);
		}
		System.out.println(fieldMap);
		
		long endTimeMillis = System.currentTimeMillis();
		System.out.println(">>> total cost : " + (endTimeMillis - startTimeMillis) + " ms");
	}
	
	/**
	 * 基于java.lang.reflect.Method的invoke()方法操作对象的属性
	 * total cost : 7300 ms AVG
	 */
	public static void testJDKReflection2() throws Exception {
		Product product = new Product();
		long startTimeMillis = System.currentTimeMillis();
		Class<?> clazz = Product.class;
		Method[] methods = clazz.getDeclaredMethods();
		Map<String,Method> methodMap = new HashMap<String,Method>();
		for(Method method : methods){
			method.setAccessible(true);
			methodMap.put(method.getName(), method);
		}
		for(int i = 0; i < 100000000; i++){
			Method getMethod = methodMap.get("getProductId");
			Object value = getMethod.invoke(product, (Object[])null);
			Method setMethod = methodMap.get("setProductId");
			setMethod.invoke(product, value);
		}
		System.out.println(methodMap);
		long endTimeMillis = System.currentTimeMillis();
		System.out.println(">>> total cost : " + (endTimeMillis - startTimeMillis) + " ms");
	}
	
	/**
	 * 基于java.beans.PropertyDescriptor操作对象的属性
	 * total cost : 7300 ms AVG
	 */
	public static void testJDKReflection3() throws Exception {
		Product product = new Product();
		long startTimeMillis = System.currentTimeMillis();
		Map<String,Method> methodMap = new HashMap<String,Method>();
		PropertyDescriptor[] pds = Introspector.getBeanInfo(Product.class, Object.class).getPropertyDescriptors();
		for(PropertyDescriptor pd : pds){
			System.out.println("property name : " + pd.getName() + ", read-method : " + pd.getReadMethod() + ", write-method : " + pd.getWriteMethod());
			Method m = pd.getWriteMethod();
			m.setAccessible(true);
			methodMap.put(m.getName(), m);
			m = pd.getReadMethod();
			m.setAccessible(true);
			methodMap.put(m.getName(), m);
		}
		for(int i = 0; i < 100000000; i++){
			Method getMethod = methodMap.get("getProductId");
			Object value = getMethod.invoke(product, (Object[])null);
			Method setMethod = methodMap.get("setProductId");
			setMethod.invoke(product, value);
		}
		long endTimeMillis = System.currentTimeMillis();
		System.out.println(">>> total cost : " + (endTimeMillis - startTimeMillis) + " ms");
	}
	
	public static void testCglibReflection() throws Exception {
		Product product = new Product();
		long startTimeMillis = System.currentTimeMillis();
		FastClass fastClass = FastClass.create(Product.class);
		Map<String,FastMethod> fastMethodMap = new HashMap<String,FastMethod>();
		PropertyDescriptor[] pds = Introspector.getBeanInfo(Product.class, Object.class).getPropertyDescriptors();
		for(PropertyDescriptor pd : pds){
			System.out.println("property name : " + pd.getName() + ", read-method : " + pd.getReadMethod() + ", write-method : " + pd.getWriteMethod());
			Method m = pd.getWriteMethod();
			fastMethodMap.put(m.getName(), fastClass.getMethod(m));
			m = pd.getReadMethod();
			fastMethodMap.put(m.getName(), fastClass.getMethod(m));
		}
		
		for(int i = 0; i < 100000000; i++){
			FastMethod getMethod = fastMethodMap.get("getProductId");
			Object value = getMethod.invoke(product, (Object[])null);
			FastMethod setMethod = fastMethodMap.get("setProductId");
			setMethod.invoke(product, new Object[]{value});
		}
		long endTimeMillis = System.currentTimeMillis();
		System.out.println(">>> total cost : " + (endTimeMillis - startTimeMillis) + " ms");
	}
	
	public static void main(String[] args) throws Exception {
		//testJDKNormalGetAndSet();
		//testJDKReflection2();
		//testJDKReflection3();
		testCglibReflection();
	}

}
